﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Interface;
using LogicAnalyzerCommon;

namespace AvrLogicAnalyzer
{
    public partial class SettingsControl : UserControl, ISettingsControl
    {
        internal const string AvrLogicAnalyzer = "AvrLogicAnalyzer";
        internal const string SampleFrequencyIndexKey = "SampleFrequencyIndex";
        internal const string SampleSizeIndexKey = "SampleSizeIndex";
        internal const string AutoEdgeChannelIndexKey = "AutoEdgeChannelIndex";
        internal const string AutoCompareTriggerLevelKey = "AutoCompareTriggerLevel";
        internal const string AutoEdgeDirectionKey = "AutoEdgeDirection";
        internal const string TriggerModeKey = "TriggerMode";
        internal const string PortNameKey = "PortName";
        internal const string PreTriggerMemoryPercentageKey = "PreTriggerMemoryPercentage";

        public IDictionary<string,string> SampleSettings
        {
            get
            {
                Dictionary<string,string> sampleSettings = new Dictionary<string,string>();

                sampleSettings.Add(Key(SampleFrequencyIndexKey), comboBoxFrequency.SelectedIndex.ToString());
                sampleSettings.Add(Key(SampleSizeIndexKey), comboBoxBufferSize.SelectedIndex.ToString());
                sampleSettings.Add(Key(AutoEdgeChannelIndexKey), comboBoxChannelEdgeNumber.SelectedIndex.ToString());
                sampleSettings.Add(Key(PortNameKey), (string)comboBoxComPort.SelectedItem);
                sampleSettings.Add(Key(AutoCompareTriggerLevelKey), AutoCompareTriggerLevel.ToString());
                sampleSettings.Add(Key(AutoEdgeDirectionKey), AutoEdgeDirection.ToString());
                sampleSettings.Add(Key(TriggerModeKey), TriggerMode.ToString());
                sampleSettings.Add(Key(PreTriggerMemoryPercentageKey), trackBarPreTriggerPercentage.Value.ToString());

                return sampleSettings;
            }
        }

        public void Init(ILogicAnalyzer logicAnalyzer, IDictionary<string, string> sampleSettings)
        {
            InitDefaultValues(logicAnalyzer);

            InitCurrentValues(sampleSettings);
        }

        public SettingsControl()
        {
            InitializeComponent();
        }

        public SettingsControl(ILogicAnalyzer logicAnalyzer, IDictionary<string, string> sampleSettings)
        {
            InitializeComponent();

            Init(logicAnalyzer, sampleSettings);
        }

        private byte AutoCompareTriggerLevel
        {
            get
            {
                byte value = 0;

                value |= (byte)((triggerLevel0.Level == Level.High) ? 1 : 0);
                value |= (byte)((triggerLevel1.Level == Level.High) ? 2 : 0);
                value |= (byte)((triggerLevel2.Level == Level.High) ? 4 : 0);
                value |= (byte)((triggerLevel3.Level == Level.High) ? 8 : 0);
                value |= (byte)((triggerLevel4.Level == Level.High) ? 16 : 0);
                value |= (byte)((triggerLevel5.Level == Level.High) ? 32 : 0);
                value |= (byte)((triggerLevel6.Level == Level.High) ? 64 : 0);
                value |= (byte)((triggerLevel7.Level == Level.High) ? 128 : 0);

                return value;
            }
            set
            {
                // Fill the channel compare radio buttons
                triggerLevel0.Level = ((value & 1) == 0) ? Level.Low : Level.High;
                triggerLevel1.Level = ((value & 2) == 0) ? Level.Low : Level.High;
                triggerLevel2.Level = ((value & 4) == 0) ? Level.Low : Level.High;
                triggerLevel3.Level = ((value & 8) == 0) ? Level.Low : Level.High;
                triggerLevel4.Level = ((value & 16) == 0) ? Level.Low : Level.High;
                triggerLevel5.Level = ((value & 32) == 0) ? Level.Low : Level.High;
                triggerLevel6.Level = ((value & 64) == 0) ? Level.Low : Level.High;
                triggerLevel7.Level = ((value & 128) == 0) ? Level.Low : Level.High;
            }
        }

        private TriggerEdge AutoEdgeDirection
        {
            set
            {
                switch (value)
                {
                    case TriggerEdge.Rising:
                        radioButtonRising.Checked = true;
                        break;
                    case TriggerEdge.Falling:
                        radioButtonFalling.Checked = true;
                        break;
                }
            }
            get
            {
                return radioButtonRising.Checked ? TriggerEdge.Rising : TriggerEdge.Falling;
            }
        }

        private TriggerMode TriggerMode
        {
            set
            {
                switch (value)
                {
                    case TriggerMode.AutoCmp:
                        radioButtonAutoCmp.Checked = true;
                        break;
                    case TriggerMode.AutoEdge:
                        radioButtonAutoEdge.Checked = true;
                        break;
                    case TriggerMode.Manual:
                        radioButtonManual.Checked = true;
                        break;
                }
            }
            get
            {
                if(radioButtonAutoCmp.Checked)
                {
                    return TriggerMode.AutoCmp;
                }
                else if (radioButtonAutoEdge.Checked)
                {
                    return TriggerMode.AutoEdge;
                }
                else
                {
                    return TriggerMode.Manual;
                }
            }
        }

        private void InitDefaultValues(ILogicAnalyzer logicAnalyzer)
        {
            triggerLevel0.Channel = 0;
            triggerLevel1.Channel = 1;
            triggerLevel2.Channel = 2;
            triggerLevel3.Channel = 3;
            triggerLevel4.Channel = 4;
            triggerLevel5.Channel = 5;
            triggerLevel6.Channel = 6;
            triggerLevel7.Channel = 7;

            // Fill the COM-port combo box
            List<string> portNames = new List<string>();
            if (logicAnalyzer.CommunicationDevices != null)
            {
                foreach (ICommunication communicationDevices in logicAnalyzer.CommunicationDevices)
                {
                    portNames.AddRange(communicationDevices.PortNames);
                }
            }
            comboBoxComPort.Items.Clear();
            if (portNames.Count == 0)
            {
                comboBoxComPort.SelectedText = "No COM-ports available            ";
                comboBoxComPort.Enabled = false;
            }
            else
            {
                comboBoxComPort.Items.AddRange(portNames.ToArray());
            }

            // Fill sample frequencies combo box
            comboBoxFrequency.Items.Clear();
            foreach (long frequency in logicAnalyzer.FrequenciesSupported)
            {
                comboBoxFrequency.Items.Add(frequency.PrettyPrintFrequency());
            }

            // Fill buffer size combo box
            comboBoxBufferSize.Items.Clear();
            foreach (long sampleSize in logicAnalyzer.SampleSizesSupported)
            {
                comboBoxBufferSize.Items.Add(sampleSize.ToString());
            }

            // Fill the channel combo box
            comboBoxChannelEdgeNumber.Items.Clear();
            for (int index = 0; index < AvrAnalyzer.NumberOfChannels; index++)
            {
                comboBoxChannelEdgeNumber.Items.Add((index + 1).ToString());
            }

            trackBarPreTriggerPercentage.Value = 0;
        }

        private void InitCurrentValues(IDictionary<string, string> sampleSettings)
        {
            SetComboBox(comboBoxFrequency, sampleSettings, SampleFrequencyIndexKey);
            SetComboBox(comboBoxBufferSize, sampleSettings, SampleSizeIndexKey);
            SetComboBox(comboBoxChannelEdgeNumber, sampleSettings, AutoEdgeChannelIndexKey);

            string portName = string.Empty;
            sampleSettings.TryGetValue(Key(PortNameKey), out portName);
            SetComPortComboBox(portName);

            AutoCompareTriggerLevel = 0;
            string value = GetValue(sampleSettings, AutoCompareTriggerLevelKey);
            if (!string.IsNullOrEmpty(value))
            {
                AutoCompareTriggerLevel = byte.Parse(value);
            }

            AutoEdgeDirection = TriggerEdge.Rising;
            value = GetValue(sampleSettings, AutoEdgeDirectionKey);
            if (!string.IsNullOrEmpty(value))
            {
                AutoEdgeDirection = (TriggerEdge)Enum.Parse(typeof(TriggerEdge), value);
            }

            TriggerMode = TriggerMode.Manual;
            value = GetValue(sampleSettings, TriggerModeKey);
            if (!string.IsNullOrEmpty(value))
            {
                TriggerMode = (TriggerMode)Enum.Parse(typeof(TriggerMode), value);
            }
            EnableTriggerGroupBox();

            value = GetValue(sampleSettings, PreTriggerMemoryPercentageKey);
            if (!string.IsNullOrEmpty(value))
            {
                trackBarPreTriggerPercentage.Value = int.Parse(value);
            }
        }

        private void SetComboBox(ComboBox comboBox, IDictionary<string, string> stringDictionary, string key)
        {
            if (comboBox.Items.Count == 0) return;

            // Select the first item when no selection was found in the dictionary
            if (!stringDictionary.ContainsKey(Key(key)))
            {
                comboBox.SelectedIndex = 0;
            }
            else // use the key found in the dictionary
            {
                int index;
                if((int.TryParse(stringDictionary[Key(key)], out index)) &&
                    (index > 0 && index < comboBox.Items.Count))  // check the range
                {
                    comboBox.SelectedIndex = index;
                }
                else
                {
                    comboBox.SelectedIndex = 0;
                }
            }
        }

        private void SetComPortComboBox(string selectedPortName)
        {
            if (comboBoxComPort.Items.Count == 0) return;

            // Restore the combo box indexes
            // No COM-port previously selected
            if (string.IsNullOrEmpty(selectedPortName))
            //if (!sampleSettings.ContainsKey(Key(PortNameKey)))
            {
                // Select the first
                comboBoxComPort.SelectedIndex = 0;
            }
            else
            {
                bool portFound = false;
                foreach (string portName in comboBoxComPort.Items)
                {
                    if (portName == selectedPortName)
                    {
                        comboBoxComPort.SelectedItem = portName;
                        portFound = true;
                        continue;
                    }
                }
                if (portFound == false)
                {
                    //MessageBox.Show(string.Format("COM-port '{0}' not found; '{1}' selected.", this.Settings.PortName, portNames[0]), MainForm.Title);
                    comboBoxComPort.SelectedIndex = 0;
                }
            }
        }

        private static string Key(string key)
        {
            return string.Format("{0}.{1}", AvrLogicAnalyzer, key);
        }

        private string GetValue(IDictionary<string, string> stringDictionary, string key)
        {
            if (stringDictionary.ContainsKey(Key(key)))
            {
                return stringDictionary[Key(key)];
            }
            return string.Empty;
        }

        private void EnableTriggerGroupBox()
        {
            if (radioButtonAutoCmp.Checked)
            {
                groupBoxAutoCmp.Enabled = true;
                groupBoxAutoEdge.Enabled = false;
            }
            else if (radioButtonAutoEdge.Checked)
            {
                groupBoxAutoCmp.Enabled = false;
                groupBoxAutoEdge.Enabled = true;
            }
            else //if(radioButtonManual.Checked)
            {
                groupBoxAutoCmp.Enabled = false;
                groupBoxAutoEdge.Enabled = false;
            }
        }

        private void radioButtonTrigger_CheckedChanged(object sender, EventArgs e)
        {
            EnableTriggerGroupBox();
        }

        private void trackBarPreTriggerPercentage_ValueChanged(object sender, EventArgs e)
        {
            UpdatePreTriggerLabel();
        }

        private void UpdatePreTriggerLabel()
        {
            int bufferSize = int.Parse((string)comboBoxBufferSize.Text);
            int preBufferSize = (int)((bufferSize / 100.0) * trackBarPreTriggerPercentage.Value);

            labelPreTriggerMemory.Text = string.Format("Pre Trigger Memory: {0}% ({1}) of ({2})", trackBarPreTriggerPercentage.Value, preBufferSize, bufferSize);
        }

        private void comboBoxBufferSize_TextChanged(object sender, EventArgs e)
        {
            UpdatePreTriggerLabel();
        }
    }
}
